package logic

import (
	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/strategy/hash"
)

// Observer提供服务，并向Watcher通知自己，实现服务注册
// 定时上报运行状态，并执行Watcher的命令

type Observer interface {
	Target() string
	Depend(agent string)
	OnObserved(fn asteroid.FinishHandler)
	OnAllocTarget(fn asteroid.FinishHandler)
	PublishPipe() *asteroid.Pipe
	GroupPublishPipe() *asteroid.Pipe
	//Send(event interface{}, data ...interface{})
	//Request(event interface{}, fn asteroid.ToCallbackHandler, data ...interface{})
	//CrossSend(info interface{}, event interface{}, data ...interface{})
	//CrossRequest(info interface{}, event interface{}, fn asteroid.ToCallbackHandler, data ...interface{})
}
type ObserverInstance struct {
	asteroid.Channel

	id      string
	groupId string
	meta    map[string]string

	publisher *asteroid.Publisher
	target    string

	observed     bool
	observedFunc []asteroid.FinishHandler
	finishFunc   []asteroid.FinishHandler
}

func NewObserver(id string, groupId string, core string, channel asteroid.Channel, meta map[string]string) *ObserverInstance {
	observer := &ObserverInstance{
		Channel:  channel,
		id:       id,
		groupId:  groupId,
		meta:     meta,
		observed: false,
	}
	observer.observedFunc = make([]asteroid.FinishHandler, 0)
	observer.finishFunc = make([]asteroid.FinishHandler, 0)

	subscriber := channel.Subscribe(core)

	subscriber.On("observer", func(message asteroid.Message) {
		watcher := message.GetOrigin()
		//fmt.Println("observer publish", observer.id, watcher, observer.Publisher == nil)
		if observer.publisher == nil {
			observer.initPublisher(watcher)
		} else {
			// 对于断线重连，不会触发onjoin事件的，主动发送
			observer.publisher.Direct(message.GetFrom()).OriginId(observer.id).Data(observer.meta).Send("watcher")
		}

		// 对于心跳检查，发送response进行激活
		message.Response(true)
	})

	return observer
}

func (observer *ObserverInstance) Target() string {
	return observer.target
}

// 关联什么服务，需要预先进行设定
func (observer *ObserverInstance) Depend(agent string) {
	publisher, ok := observer.Publish(agent)
	if !ok {
		publisher.SetStrategy(hash.NewStrategy())
	}
	// 发送给core注册关系
	// todo core进行处理
	observer.Send("relation", observer.id, agent)
}

func (observer *ObserverInstance) initPublisher(watcher string) {
	publisher, ok := observer.Publish(watcher)
	//fmt.Println("observer publish", observer.id, watcher, ok)
	if !ok {
		publisher.SetStrategy(hash.NewStrategy())
	}
	observer.publisher = publisher
	number := 0
	finish := 0
	observer.publisher.OnJoin(func(node string) {
		// 对于每个联入的都发送
		//fmt.Println("<= observer meta join", observer.id, watcher, observer.Node(), node)
		number += 1
		observer.publisher.Direct(node).OriginId(observer.id).Data(observer.meta).CallbackTo(func(success bool, data interface{}) {
			finish += 1
			if number == finish {
				observer.onFinish()
				number = 0
				finish = 0
			}
		}).Send("watcher")
	})
	observer.publisher.OnFinish(func() {
		if number == finish {
			observer.onFinish()
			number = 0
			finish = 0
		}
		//fmt.Println("observer init ", observer.id, watcher, observer.Publisher)
	})
}

// 判断注册成功后执行完成事件
func (observer *ObserverInstance) onFinish() {
	// 管理端按observer名称进行负载均衡划分
	observer.target = observer.publisher.Alloc(observer.id)
	for key, _ := range observer.finishFunc {
		observer.finishFunc[key]()
	}
	if !observer.observed {
		observer.observed = true
		for key, _ := range observer.observedFunc {
			observer.observedFunc[key]()
		}
		//fmt.Println("= observer observed", observer.id, watcher, observer.Node())
	}
}

// 关联上watcher后
func (observer *ObserverInstance) OnObserved(f asteroid.FinishHandler) {
	observer.observedFunc = append(observer.observedFunc, f)
	if observer.observed {
		f()
	}
}

func (observer *ObserverInstance) OnAllocTarget(f asteroid.FinishHandler) {
	observer.finishFunc = append(observer.finishFunc, f)
	if observer.observed {
		f()
	}
}

func (observer *ObserverInstance) PublishPipe() *asteroid.Pipe {
	if observer.publisher == nil {
		// 注册一个空的pipe
		return observer.Pipe("")
	}
	return observer.publisher.Direct(observer.target).OriginId(observer.id)
}

func (observer *ObserverInstance) GroupPublishPipe() *asteroid.Pipe {
	if observer.publisher == nil {
		// 注册一个空的pipe
		return observer.Pipe("")
	}
	return observer.publisher.Direct(observer.target).OriginId(observer.groupId)
}

func (observer *ObserverInstance) Send(event interface{}, data ...interface{}) {
	if observer.publisher == nil {
		return
	}
	observer.publisher.Direct(observer.target).OriginId(observer.id).List(data...).Send(event)
}

func (observer *ObserverInstance) GrouupSend(event interface{}, data ...interface{}) {
	if observer.publisher == nil {
		return
	}
	observer.publisher.Direct(observer.target).OriginId(observer.groupId).List(data...).Send(event)
}
